﻿using System;
using System.Collections.Generic;
using ku.reformatter.contract;
using ku.datamodel.contract;

using System.Linq;


namespace ku.reformatter
{
    public class Reformatter : IReformatter
    {
        private static int GetTokenLength(Token token)
        {
            switch (token.Typ)
            {
                case TokenType.Absatzende:
                case TokenType.Textende:
                    return 0;

                case TokenType.Softtrenner:
                    return 1;

                case TokenType.Wort:
                case TokenType.Satzzeichen:
                case TokenType.Whitespace:
                    return token.Inhalt.Length;

                default:
                    return 0;
            }
        }

        private static string GetTokenText(Token token)
        {
            switch (token.Typ)
            {
                case TokenType.Absatzende:
                    return Environment.NewLine + Environment.NewLine;

                case TokenType.Textende:
                    return "";

                case TokenType.Softtrenner:
                    return "-";

                case TokenType.Wort:
                case TokenType.Satzzeichen:
                case TokenType.Whitespace:
                    return token.Inhalt;
                   
                default:
                    return "";
            }
        }


        private static int GetNextFragmentLength(Token thisToken , Token nextToken )
        {
            if (thisToken.Typ == TokenType.Wort &&
                nextToken.Typ == TokenType.Softtrenner)
            {
                return GetTokenLength(thisToken) + GetTokenLength(nextToken);
            }
            return GetTokenLength(thisToken);
        }


        public string Reformat(IEnumerable<Token> tokens, int zeilenlaenge)
        {   
            int currentLineLength = 0;
            string result = "";
            bool wordBreakPending = false;

            Token thisToken = null;
            Token nextToken = null;

            foreach( Token t in tokens )
            {
                thisToken = nextToken;
                nextToken = t;

                if ( thisToken == null )
                    continue;   // foreach

                if ( currentLineLength + GetNextFragmentLength( thisToken,nextToken ) > zeilenlaenge )
                {
                    if ( wordBreakPending )
                    {
                        result = result + "-";
                    }

                    if (currentLineLength > 0)
                    {
                        currentLineLength = 0;
                        result += Environment.NewLine;
                    }
                    wordBreakPending = false;
                }


                switch( thisToken.Typ )
                {
                    case TokenType.Whitespace:
                        if ( currentLineLength == 0 && GetTokenLength( thisToken ) == 1 )
                        {

                        }
                        else
                        {
                            result = result + GetTokenText(thisToken);
                            currentLineLength += GetTokenLength(thisToken);
                            wordBreakPending = false;                            
                        }

                        break;

                    case TokenType.Absatzende:
                        result = result + GetTokenText(thisToken);
                        currentLineLength = 0;
                        break;

                    case TokenType.Satzzeichen:
                        result = result + GetTokenText(thisToken);
                        currentLineLength += GetTokenLength(thisToken);
                        break;

                    case TokenType.Wort:
                    
                        if ( currentLineLength + GetNextFragmentLength(thisToken, nextToken) > zeilenlaenge)
                        {
                            // have to chop word at max line width
                            string veryLongWord = thisToken.Inhalt;

                            while( currentLineLength + veryLongWord.Length > zeilenlaenge)
                            {
                                result += veryLongWord.Substring(0, zeilenlaenge - currentLineLength) + Environment.NewLine;
                                veryLongWord = veryLongWord.Substring(zeilenlaenge - currentLineLength);
                                currentLineLength = 0;
                            }

                            result += veryLongWord;
                            currentLineLength = veryLongWord.Length;        
                        }
                        else
                        {
                            result = result + GetTokenText(thisToken);
                            currentLineLength += GetTokenLength(thisToken);                            
                        }


                        if (nextToken.Typ == TokenType.Softtrenner)
                        {
                            wordBreakPending = true;
                        }
                        else
                        {
                            wordBreakPending = false;                            
                        }
                        break;
                    case TokenType.Softtrenner:
                        break;
                }
           
            }

            return result;
        }
 
    }
}
